import { Menu, Icon } from 'ant-design-vue'
import ProIcon from '@/components/Icon/icon.vue'
import { isArray, validateURL as isExternalLink } from '@guanwei/app-javascript'

/** @type {import('vue').ComponentOptions} */
const SiderMenu = {
  name: 'ProSiderMenu',
  props: {
    data: {
      type: Array,
      default: () => []
    },
    selectedKey: String,
    collapsed: Boolean,
    theme: {
      type: String,
      default: 'dark',
      validator: v => ['light', 'dark'].includes(v)
    }
  },
  data() {
    return {
      openKeys: [],
      cacheOpenKeys: []
    }
  },
  computed: {
    reSelectedKeys: {
      set(keys) {
        const key = keys && keys.length ? keys[0] : ''
        this.$emit('update:selectedKey', key)
      },
      get() {
        this.setOpenKeys()
        return this.selectedKey ? [ this.selectedKey ] : []
      }
    },
    rootSubmenuKeys() {
      return this.data.map(({ path }) => path)
    },
    menuOpenKeys() {
      return flatMenus(this.data)
    }
  },
  watch: {
    collapsed(value) {
      if (value) {
        this.cacheOpenKeys = this.openKeys
        this.openKeys = []
      } else {
        this.openKeys = this.cacheOpenKeys
      }
    }
  },
  methods: {
    handleOpen({ key: path }) {
      const { fullPath, meta } = this.$route
      if (fullPath === path) {
        meta.refresh && this.$store.dispatch('tagsView/delCachedView', this.$route).then(() => {
          this.$router.replace({
            path: '/redirect' + path
          })
        })
      } else {
        path = path + ''
        isExternalLink(path)
          ? !this.$isServer && window.open(path)
          : this.$router.push(path)
      }
    },
    setOpenKeys() {
      const selectedKey = this.selectedKey ? this.menuOpenKeys[this.selectedKey] : undefined
      if (this.collapsed) {
        this.cacheOpenKeys = selectedKey
      } else {
        this.openKeys = selectedKey
      }
    }
  },
  render() {
    const renderInner = item => {
      const { meta } = item
      const vnodes = []
      let icon = meta?.icon
      if (icon) {
        const isCustomIcon = icon.startsWith('#')
        icon = isCustomIcon ? icon.slice(1) : icon
        vnodes.push(isCustomIcon ? <ProIcon type={ icon } /> : <Icon type={ icon }/>)
      }
      vnodes.push(<span>{ meta?.title ?? '' }</span>)
      return vnodes
    }
    const renderItem = data => {
      return data.filter(r => !r.hidden).map(item => {
        return item.children && item.children.length
          ? (
            <Menu.SubMenu key={ item.path } scopedSlots={ { title: () => renderInner(item) }}>
              { renderItem(item.children) }
            </Menu.SubMenu>
          )
          : <Menu.Item key={ item.path }>{ renderInner(item) }</Menu.Item>
      })
    }

    const menuProps = {
      props: {
        mode: 'inline',
        theme: this.theme,
        openKeys: this.openKeys,
        selectedKeys: this.reSelectedKeys,
        inlineCollapsed: this.collapsed
      },
      on: {
        click: item => this.handleOpen(item),
        selectChange: value => { this.reSelectedKeys = value },
        openChange: keys => {
          const latestOpenKey = keys.find(key => !this.openKeys?.includes?.(key))
          if (!latestOpenKey || !this.rootSubmenuKeys.includes(latestOpenKey)) {
            this.openKeys = keys
          } else {
            this.openKeys = latestOpenKey ? [ latestOpenKey ] : []
          }
        }
      }
    }

    return <Menu { ...menuProps }>{ renderItem(this.data) }</Menu>
  }
}

export default SiderMenu

function flatMenus(menus, root = []) {
  let raw = {}

  menus.forEach(menu => {
    raw[menu.path] = [...root, menu.path]
    if (isArray(menu.children) && menu.children.length) {
      raw = { ...raw, ...flatMenus(menu.children, raw[menu.path]) }
    }
  })

  return raw
}
